package com.weijianhuawen.wjblog.search.helper;

import com.google.common.collect.Lists;
import com.weijianhuawen.wjblog.search.config.LuceneProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.print.Doc;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;

/**
 * @version: java version 8
 * @Author: weijianhuawen
 * @description:
 * @date: 2024-11-04 17:51
 */

@Component
@Slf4j
public class LuceneHelper {
    @Autowired
    private LuceneProperties luceneProperties;
    //创建索引
    /**
     * 创建索引
     * @param index 索引位置
     * @param documents 对应索引
     */
    public void createIndex(String index, List<Document> documents) {
        try {
            // 索引目录不应当对外暴露，在内部生成
            String indexDir = luceneProperties.getIndexDir() + File.separator + index;
            File dir = new File(indexDir);
            // 判断索引目录是否存在
            if (dir.exists()) {
                // 删除目录中的内容
                FileUtils.cleanDirectory(dir);
            } else {
                // 创建目录
                FileUtils.forceMkdir(dir);
            }

            // 读取索引目录
            Directory directory = FSDirectory.open(Paths.get(indexDir));
            // 中文分析器
            Analyzer analyzer = new SmartChineseAnalyzer();
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
            // 创建索引
            IndexWriter writer = new IndexWriter(directory, indexWriterConfig);

            // 添加文档
            documents.forEach(document -> {
                try {
                    writer.addDocument(document);
                } catch (IOException e) {
                    log.error("【LuceneHelper】 添加 Lucene 文档时 出现异常！", e);
                }
            });

            // 提交
            writer.commit();
            writer.close();
        } catch (Exception e) {
            log.error("【LuceneHelper】创建 Lucene 索引失败！", e);
        }
    }

    // 查询文档总数

    /**
     * 关键词搜索 查询数据总量
     * @param index 索引对应的表
     * @param word 查询关键词
     * @param columns 需要搜索的字段
     * @return 记录总数
     */
    public Long searchTotal(String index, String word, String[] columns) {
        try {
            String indexDir = luceneProperties.getIndexDir() + File.separator + index;
            // 打开索引目录
            Directory directory = FSDirectory.open(Paths.get(indexDir));
            IndexReader reader = DirectoryReader.open(directory);
            IndexSearcher searcher = new IndexSearcher(reader);

            // 中文分析器
            Analyzer analyzer = new SmartChineseAnalyzer();
            // 查询解析器
            QueryParser parser = new MultiFieldQueryParser(columns, analyzer);
            // 解析查询关键字
            Query query = parser.parse(word);

            // 搜索文档
            TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
            // 返回文档数
            return topDocs.totalHits.value;
        } catch (Exception e) {
            log.info("【LUCENE Helper】 查询Lucene错误！", e);
            return 0L;
        }
    }

    // 分页搜索
    /**
     *  关键词搜索
     * @param index  索引目录
     * @param word 查询关键词
     * @param columns 被搜索的字段
     * @param current 当前页
     * @param size 当前页数据量
     * @return 数据
     */
    public List<Document> search(String index, String word, String[] columns, Integer current, Integer size) {
        if (current <= 0) current = 1;
        if (size < 0) size = 0;
        try {
            String indexDir = luceneProperties.getIndexDir() + File.separator + index;
            // 打开索引目录
            Directory directory = FSDirectory.open(Paths.get(indexDir));
            // 读取目录
            IndexReader reader = DirectoryReader.open(directory);
            // 创建搜索引擎
            IndexSearcher searcher = new IndexSearcher(reader);

            // 中文解析器
            Analyzer analyzer = new SmartChineseAnalyzer();
            // 创建查询解析器
            QueryParser parser = new MultiFieldQueryParser(columns, analyzer);
            // 解析关键词
            Query query = parser.parse(word);

            // 分页搜索
            Integer limit = current * size;
            log.info("limit : {}", limit);
            TopDocs topDocs = searcher.search(query, limit);

            // 匹配文档数组
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
            // 计算分页起始点 和 结束点
            Integer start  = (current - 1) * size;
            Integer end = Math.min(start + size, scoreDocs.length);

            // 返回指定页码
            List<Document> documents = Lists.newArrayList();
            for (int i = start; i < end; i++) {
                Document document = searcher.doc(scoreDocs[i].doc);
                documents.add(document);
            }
            // 释放资源
            reader.close();
            return documents;
        } catch (Exception e) {
            log.error("【LUCENE Helper】 查询Lucene错误！", e);
            return null;
        }
    }

    // 添加文档

    /**
     * 添加索引
     * @param index 索引名
     * @param document 文档
     * @return 结果
     */
    public Long addDocument(String index, Document document) {
        try {
            String indexDir = luceneProperties.getIndexDir() + File.separator + index;

            Directory directory = FSDirectory.open(Paths.get(indexDir));
            // 配置indexWriter
            Analyzer analyzer = new SmartChineseAnalyzer();
            IndexWriterConfig config = new IndexWriterConfig(analyzer);
            IndexWriter writer  = new IndexWriter(directory, config);

            // 添加文档
            Long count = writer.addDocument(document);
            writer.commit();
            writer.close();
            return count;

        } catch (Exception e) {
            log.error("【LUCENE Helper】 添加Luncene 失败！");
            return 0L;
        }
    }
    // 删除文档

    /**
     * 删除文档
     * @param index 索引名
     * @param term 删除条件
     * @return 影响数据条数
     */
    public Long deleteDocument(String index, Term term) {
        try {
            String indexDir = luceneProperties.getIndexDir() + File.separator + index;

            Directory directory = FSDirectory.open(Paths.get(indexDir));

            // 配置index writer
            IndexWriterConfig config = new IndexWriterConfig(new SmartChineseAnalyzer());
            IndexWriter writer = new IndexWriter(directory, config);

            // 删除文档
            Long count = writer.deleteDocuments(term);
            writer.commit();
            writer.close();
            return count;
        } catch (Exception e) {
            log.error("【LUCENE Helper】 删除文档失败!", e);
            return 0L;
        }
    }

    // 更新文档

    /**
     * 更新文档
     * @param index 索引
     * @param document 文档
     * @param term 匹配条件
     * @return 受影响数据条数
     */
    public Long updateDocument(String index, Document document, Term term) {
        try {
            String indexDir = luceneProperties.getIndexDir() + File.separator + index;
            Directory directory = FSDirectory.open(Paths.get(indexDir));

            IndexWriterConfig config = new IndexWriterConfig(new SmartChineseAnalyzer());
            IndexWriter writer = new IndexWriter(directory, config);

            Long count = writer.updateDocument(term, document);
            // 提交
            writer.commit();
            writer.close();
            return count;
        } catch (Exception e) {
            log.error("【LUCENE Helper】 文档修改失败！" + e);
            return 0L;
        }
    }
}
